图像和内存

我们在Nibabel图像中看到,从磁盘加载的图像通常是代理图像。代理映像是具有dataobj不是numpy数组属性的映像,而是可以从磁盘读取数组数据的数组代理

>>> import os
>>> import numpy as np
>>> from nibabel.testing import data_path
>>> example_file = os.path.join(data_path, 'example4d.nii.gz')
>>> import nibabel as nib
>>> img = nib.load(example_file)
>>> img.dataobj
<nibabel.arrayproxy.ArrayProxy object at ...>

load图像时,Nibabel不会从代理加载图像数组。它等待,直到你问阵列数据。要求数组数据的标准方法是调用该get_data()方法:

>>> data = img.get_data()
>>> data.shape
(128, 96, 24, 2)

我们还在代理和缓存中看到,这个调用get_data()将(默认情况下)将数组数据加载到内部图像缓存中。该图像将下一次调用的缓存副本返回到get_data()

>>> data_again = img.get_data()
>>> data is data_again
True

如果您想快速重复访问图像数组数据,则此行为非常方便。不利的一面是图像保留了对图像数据数组的引用,因此在删除图像对象之前,数组不能从内存中清除。您可能更喜欢从磁盘继续加载数组,而不是将缓存的副本保留在图像中。

本页介绍使用图像阵列代理来节省内存和时间的方法。

使用in_memory来检查高速缓存的状态

您可以使用该in_memory属性来检查图像是否缓存了数组。

in_memory属性对于数组图像始终为True,因为图像数据始终是内存中的一个数组:

>>> array_data = np.arange(24, dtype=np.int16).reshape((2, 3, 4))
>>> affine = np.diag([1, 2, 3, 1])
>>> array_img = nib.Nifti1Image(array_data, affine)
>>> array_img.in_memory
True

对于代理映像,in_memory当数组不在缓存中时属性为False,在缓存中为True时:

>>> img = nib.load(example_file)
>>> img.in_memory
False
>>> data = img.get_data()
>>> img.in_memory
True

使用uncache

大家知道,代理映像有get_data()缓存中的数组,返回缓存数组:

>>> data_again = img.get_data()
>>> data_again is data  # same array returned from cache
True

您可以使用以下uncache()方法解包代理映像:

>>> img.uncache()
>>> img.in_memory
False
>>> data_once_more = img.get_data()
>>> data_once_more is data  # a new copy read from disk
False

uncache()如果图像是数组图像,或者缓存已经是空的,则不起作用。

修改get_data()代理映像返回的数组时,需要小心,因为这样uncache会更改从get_data()以下位置返回的结果:

>>> proxy_img = nib.load(example_file)
>>> data = proxy_img.get_data()  # array cached and returned
>>> data[0, 0, 0, 0]
0
>>> data[0, 0, 0, 0] = 99  # modify returned array
>>> data_again = proxy_img.get_data()  # return cached array
>>> data_again[0, 0, 0, 0]  # cached array modified
99

到目前为止,代理图像的行为与数组图像相同。uncache()对数组图像没有任何影响,但它对代理图像的返回数组有影响:

>>> proxy_img.uncache()  # cached array discarded from proxy image
>>> data_once_more = proxy_img.get_data()  # new copy of array loaded
>>> data_once_more[0, 0, 0, 0]  # array modifications discarded
0

节省内存

取消数组

如果您不希望图像将数组保存在其内部缓存中,则可以使用以下uncache()方法:

>>> img.uncache()

使用数组代理而不是get_data()

dataobj代理映像的属性是一个数组代理。我们可以请求代理直接返回数组传递dataobj给numpyasarray函数:

>>> proxy_img = nib.load(example_file)
>>> data_array = np.asarray(proxy_img.dataobj)
>>> type(data_array)
<... 'numpy.ndarray'>

这也适用于阵列图像,因为np.asarray返回数组:

>>> array_img = nib.Nifti1Image(array_data, affine)
>>> data_array = np.asarray(array_img.dataobj)
>>> type(data_array)
<... 'numpy.ndarray'>

如果你想避免缓存,你可以避免get_data()和总是使用np.asarray(img.dataobj)

使用caching关键字get_data()

get_data()函数的默认行为是始终填充缓存,如果它是空的。这对应于关键字的默认'fill'caching。所以这:

>>> proxy_img = nib.load(example_file)
>>> data = proxy_img.get_data()  # default caching='fill'
>>> proxy_img.in_memory
True

是这样的:

>>> proxy_img = nib.load(example_file)
>>> data = proxy_img.get_data(caching='fill')
>>> proxy_img.in_memory
True

有时你可能想避免填充缓存,如果它是空的。在这种情况下,您可以使用caching='unchanged'

>>> proxy_img = nib.load(example_file)
>>> data = proxy_img.get_data(caching='unchanged')
>>> proxy_img.in_memory
False

caching='unchanged'如果缓存已满,将会保持缓存满。

>>> data = proxy_img.get_data(caching='fill')
>>> proxy_img.in_memory
True
>>> data = proxy_img.get_data(caching='unchanged')
>>> proxy_img.in_memory
True

看到更多的细节。get_data()docstring

节省时间和内存

您可以使用阵列代理以有效的方式从磁盘获取片段。

数组代理API允许您在代理上进行切片。在大多数情况下,这意味着您只能从实际需要的磁盘加载数据,通常会节省时间和内存。

例如,让我们说你只想从示例数据集的第二卷。你可以这样做:

>>> proxy_img = nib.load(example_file)
>>> data = proxy_img.get_data()
>>> data.shape
(128, 96, 24, 2)
>>> vol1 = data[..., 1]
>>> vol1.shape
(128, 96, 24)

问题是,你必须将整个数据数组加载到内存中,然后丢弃第一个数据块并保留第二个数据块。

您可以使用阵列代理切片来更有效地执行此操作:

>>> proxy_img = nib.load(example_file)
>>> vol1 = proxy_img.dataobj[..., 1]
>>> vol1.shape
(128, 96, 24)

切入调用将只加载您需要填充内存的磁盘中的数据。proxy_img.dataobj[...,1]vol1

results matching ""

    No results matching ""